import asyncio
import logging
from pymodbus.server import StartAsyncTcpServer
from pymodbus.datastore import ModbusSequentialDataBlock, ModbusSparseDataBlock
from pymodbus.datastore import ModbusSlaveContext, ModbusServerContext
from pymodbus.device import ModbusDeviceIdentification

# 服务器监听的 IP 和端口
HOST = "0.0.0.0"  # 监听所有网络接口
# HOST = "192.168.1.235"  # 监听所有网络接口
PORT = 502  # Modbus TCP 标准端口

# 设置日志
# 创建主日志记录器
logging.basicConfig(
    format="%(asctime)s [%(levelname)s] %(message)s",
    level=logging.DEBUG,  # 调整日志级别为 DEBUG 以查看所有通信细节
)

# 启用 pymodbus 的通信日志
logging.getLogger("pymodbus").setLevel(logging.DEBUG)
logging.getLogger("pymodbus.server").setLevel(logging.DEBUG)
logging.getLogger("pymodbus.protocol").setLevel(logging.DEBUG)
logging.getLogger("pymodbus.transaction").setLevel(logging.DEBUG)


class MySparseDataBlock(ModbusSparseDataBlock):
    def getValues(self, address, count=1):
        return [self.values.get(address + i, 0) for i in range(count)]


# 创建数据存储区

spare_dl = {10: [True, True, True, False], 30: True, 40: [True] * 20}
spare_co = {10: [True, True, True, False], 30: True, 40: [True] * 20}
spare_hr = {501: [0, 0, 0], 524: [2025, 5, 31, 12, 13, 14]}
spare_ir = {
    2 + 1: 12,  # 电池堆电压/SystemTotalVoltage---------2
    3 + 1: 33333,  # 电池堆电流/SystemTotalCurrent----------3
    4 + 1: 86,  # 电池堆SOC/SystemSOC--------------------4
    5 + 1: 160,  # 电池堆SOH/SystemSOH

    6 + 1: 3345,  # 最高电池电压/MaxCellVoltage
    9 + 1: 2456,  # 最低电池电压/MinCellVoltage
    12 + 1: 132,  # 最高电池温度/MaxCellTemperature
    15 + 1: 13,  # 最低电池温度/MinCellTemperature

    16 + 1: 0,  # 最低温度电池组号
    17 + 1: 0,  # 最低温度电池所在组中的点号
    #
    18 + 1: [1, 65535],  # 堆累计充电电量--------10
    20 + 1: [1, 65535],  # 堆累计放电电量--------11
    #
    22 + 1: [0, 65535],  # 堆单次累计充电电量
    24 + 1: [0, 65535],  # 堆单次累计放电电量
    26 + 1: [10, 1],  # 堆可充电电量
    28 + 1: [20, 1],  # 堆可放电电量
    #
    32 + 1: 8000,  # 允许最大放电功率
    33 + 1: 6000,  # 允许最大充电功率

    34 + 1: 65535,  # 允许最大放电电流-----------------7
    35 + 1: 65535,  # 允许最大充电电流-----------------6
    #
    38 + 1: [0, 65535],  # 当天放电电量--------9
    40 + 1: [0, 65535],  # 当天充电电量--------8
    #
    42 + 1: 100,  # 运行温度
    43 + 1: 3,  # BMS堆当前状态:-------5
    #
    44 + 1: 6,  # BMS充放电状态:1:关机/2:满放/3:放电/4:充电/5:满充/6:静置
    # 45: 0,  # 电池堆绝缘电阻
    #
    53 + 1: 0,  # 堆连接失败原因
    54 + 1: 0,  # 心跳
}
store = ModbusSlaveContext(
    di=MySparseDataBlock(spare_dl),  # Sparse Discrete Inputs
    co=MySparseDataBlock(spare_co),  # Sparse Coils
    hr=MySparseDataBlock(spare_hr),  # Sparse Holding Registers
    ir=MySparseDataBlock(spare_ir),  # Sparse Input Registers
)


multi_store = {}
for i in range(1, 7):
    multi_store[i] = store
context = ModbusServerContext(slaves=multi_store, single=False)

# 设备标识信息（可选）
identity = ModbusDeviceIdentification()
identity.VendorName = "MyCompany"
identity.ProductCode = "ModbusRTUServer"
identity.VendorUrl = "https://example.com"
identity.ProductName = "Modbus RTU Server"
identity.ModelName = "ModbusRTU v1.0"
identity.MajorMinorRevision = "1.0"


# 启动 Modbus TCP 服务器
async def run_server():
    logging.info(f"Starting Modbus TCP Server on {HOST}:{PORT}...")
    server = await StartAsyncTcpServer(context=context, identity=identity, address=(HOST, PORT))

    try:
        await server.serve_forever()
    except asyncio.CancelledError:
        server.close()
        await server.wait_closed()


if __name__ == "__main__":
    try:
        asyncio.run(run_server())
    except KeyboardInterrupt:
        logging.info("Server is shutting down...")
